﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace CodeUtils
{
    public enum ValidationTypes
    {
        PositiveDecimal,
        Decimal,
        PositiveNonDecimal,
        NonDecimal,
        DatesDDMMYYYY,
        DatesDDMMYY,
        DatesDD_MMM_YYYY,
        Email,
        IPAddress,
        URL
    }

    /// <summary>
    /// To Validate strings against Regular Expression strings.
    /// </summary>

    public class RegExValidate
    {
        public const string EmailAddressRegex = @"^([a-zA-Z0-9_'+*$%\^&!\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9:]{2,4})+$";
        public const string CurrencyRegex = @"(^\$?(?!0,?\d)\d{1,3}(,?\d{3})*(\.\d\d)?)$";
        public const string DateRegex =
            @"^(((0?[1-9]|[12]\d|3[01])[\.\-\/](0?[13578]|1[02])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|[12]\d|30)[\.\-\/](0?[13456789]|1[012])[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|((0?[1-9]|1\d|2[0-8])[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?\d{2}|\d))|(29[\.\-\/]0?2[\.\-\/]((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00|[048])))$";
        public const string NumericRegex = @"\d*";

        /// <summary>
        /// Validates an argument is not null or empty.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentNotNullOrEmpty(string value, string parameterName)
        {
            if (value == null)
                throw new ArgumentNullException(parameterName);

            if (value.Length == 0)
                throw new ArgumentException(string.Format("'{0}' cannot be empty.", parameterName), parameterName);
        }

        public static bool NullStringCheck(string value)
        {
            if (value == null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        ///// <summary>
        ///// Validates an argument is not null or empty or whitespace.
        ///// </summary>
        ///// <param name="value">The value.</param>
        ///// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentNotNullOrEmptyOrWhitespace(string value, string parameterName)
        {
            ArgumentNotNullOrEmpty(value, parameterName);

            if (StringUtils.IsWhiteSpace(value))
                throw new ArgumentException(string.Format("'{0}' cannot only be whitespace.", parameterName), parameterName);
        }

        /// <summary>
        /// Validates a type argument is an enum.
        /// </summary>
        /// <param name="type">The type argument.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentTypeIsEnum(Type type, string parameterName)
        {
            ArgumentNotNull(type, "type");

            if (!type.IsEnum)
                throw new ArgumentException(string.Format("Type {0} is not an Enum.", type), parameterName);
        }

        /// <summary>
        /// Validates a collection argument is not null or empty.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentNotNullOrEmpty<T>(ICollection<T> collection, string parameterName)
        {
            ArgumentNotNullOrEmpty<T>(collection, parameterName, string.Format("Collection '{0}' cannot be empty.", parameterName));
        }

        /// <summary>
        /// Validates a collection argument is not null or empty.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="failureMessage">The failure message.</param>
        public static void ArgumentNotNullOrEmpty<T>(ICollection<T> collection, string parameterName, string failureMessage)
        {
            if (collection == null)
                throw new ArgumentNullException(parameterName);

            if (collection.Count == 0)
                throw new ArgumentException(failureMessage, parameterName);
        }

        /// <summary>
        /// Validates a collection argument is not null or empty.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName)
        {
            ArgumentNotNullOrEmpty(collection, parameterName, string.Format("Collection '{0}' cannot be empty.", parameterName));
        }

        /// <summary>
        /// Validates a collection argument is not null or empty.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="failureMessage">The failure message.</param>
        public static void ArgumentNotNullOrEmpty(ICollection collection, string parameterName, string failureMessage)
        {
            if (collection == null)
                throw new ArgumentNullException(parameterName);

            if (collection.Count == 0)
                throw new ArgumentException(failureMessage, parameterName);
        }

        /// <summary>
        /// Validates an argument is not null.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentNotNull(object value, string parameterName)
        {
            if (value == null)
                throw new ArgumentNullException(parameterName);
        }

        /// <summary>
        /// Validates an argument is not negative.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentNotNegative<T>(int value, string parameterName) where T : struct, IComparable<T>
        {
            ArgumentNotNegative<T>(value, parameterName, "Argument cannot be negative.");
        }

        /// <summary>
        /// Validates an argument is not negative.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="failureMessage">The failure message.</param>
        public static void ArgumentNotNegative<T>(int value, string parameterName, string failureMessage) where T : struct, IComparable<T>
        {
            if (value.CompareTo(default(T)) == -1)
                throw new ArgumentOutOfRangeException(parameterName, value, failureMessage);
        }

        /// <summary>
        /// Validates an argument is not zero.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentNotZero<T>(T value, string parameterName) where T : struct, IComparable<T>
        {
            ArgumentNotZero<T>(value, parameterName, "Argument cannot be zero.");
        }

        /// <summary>
        /// Validates an argument is not zero.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="failureMessage">The failure message.</param>
        public static void ArgumentNotZero<T>(T value, string parameterName, string failureMessage) where T : struct, IComparable<T>
        {
            if (value.CompareTo(default(T)) == 0)
                throw new ArgumentOutOfRangeException(parameterName, value, failureMessage);
        }

        /// <summary>
        /// Validates an argument is positive.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        public static void ArgumentIsPositive<T>(T value, string parameterName) where T : struct, IComparable<T>
        {
            ArgumentIsPositive<T>(value, parameterName, "Positive number required.");
        }

        /// <summary>
        /// Validates an argument is positive.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="failureMessage">The failure message.</param>
        public static void ArgumentIsPositive<T>(T value, string parameterName, string failureMessage) where T : struct, IComparable<T>
        {
            if (value.CompareTo(default(T)) != 1)
                throw new ArgumentOutOfRangeException(parameterName, value, failureMessage);
        }

        /// <summary>
        /// Validates an object is not disposed.
        /// </summary>
        /// <param name="disposed">A flag indicating whether the object is dispoed.</param>
        /// <param name="objectType">Type of the object.</param>
        public static void ObjectNotDisposed(bool disposed, Type objectType)
        {
            if (disposed)
                throw new ObjectDisposedException(objectType.Name);
        }

        /// <summary>
        /// Validates that an argument condition is true.
        /// </summary>
        /// <param name="condition">The argument condition.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="failureMessage">The failure message.</param>
        public static void ArgumentConditionTrue(bool condition, string parameterName, string failureMessage)
        {
            if (!condition)
                throw new ArgumentException(failureMessage, parameterName);
        }

        String MDYToDMY(String input)
        {
            return Regex.Replace(input, @"\b(?<month>\d{1,2})/(?<day>\d{1,2}/(?<year>\d{4})\b", "${day}-${month}-${year}");
        }

        static ArrayList RegexStrings;
        static RegExValidate()
        {
            RegexStrings = new ArrayList();
            //PositiveNumber
            RegexStrings.Insert((int)ValidationTypes.PositiveDecimal,
             @"^[0-9][0-9]*(\.[0-9]*)?$");
            //Number
            RegexStrings.Insert((int)ValidationTypes.Decimal,
             @"^(\+|-)?[0-9][0-9]*(\.[0-9]*)?$");
            //PositiveNonDecimal
            RegexStrings.Insert((int)ValidationTypes.PositiveNonDecimal,
             @"^[0-9][0-9]*$");
            //NonDecimal
            RegexStrings.Insert((int)ValidationTypes.NonDecimal,
             @"^(\+|-)?[0-9][0-9]*(\.[0-9]*)?$");
            //Dates(DD/MM/YYYY)
            RegexStrings.Insert((int)ValidationTypes.DatesDDMMYYYY,
             @"((0[1-9]|[12][0-9]|3[01]))[/|-](0[1-9]|1[0-2])
		[/|-]((?:\d{4}|\d{2}))");
            //Dates(DD/MM/YY)
            RegexStrings.Insert((int)ValidationTypes.DatesDDMMYY,
             @"((0[1-9]|[12][0-9]|3[01]))[/|-](0[1-9]|1[0-2])[/|-]((?:\d{2}))");
            //Dates(DD MMM YYYY)
            RegexStrings.Insert((int)ValidationTypes.DatesDD_MMM_YYYY,
             @"^((31(?!\ (Feb(ruary)?|Apr(il)?|June?|
		(Sep(?=\b|t)t?|Nov)(ember)?)))|
	 	((30|29)(?!\ Feb(ruary)?))|(29(?=\ 
		Feb(ruary)?\ (((1[6-9]|[2-9]\d)(0[48]|
		[2468][048]|[13579][26])|((16|[2468][048]|
		[3579][26])00)))))|(0?[1-9])|1\d|2[0-8])\ 
		(Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|
		Ju((ly?)|(ne?))|Aug(ust)?|
		Oct(ober)?|(Sep(?=\b|t)t?|Nov|Dec)(ember)?)\ 
		((1[6-9]|[2-9]\d)\d{2})");
            //Email
            RegexStrings.Insert((int)ValidationTypes.Email,
              @"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|
		(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})");
            //IPAddress
            RegexStrings.Insert((int)ValidationTypes.IPAddress,
              @"(?<First>2[0-4]\d|25[0-5]|[01]?\d\d?)\.(?<Second>
		2[0-4]\d|25[0-5]|[01]?\d\d?)\.(?<Third>
		2[0-4]\d|25[0-5]|[01]?\d\d?)\.
		(?<Fourth>2[0-4]\d|25[0-5]|[01]?\d\d?)");
            //URL
            RegexStrings.Insert((int)ValidationTypes.URL,
              @"(?\w+):\/\/(?<Domain>[\w.]+\/?)\S*");
        }

        /// <summary>
        /// Method returns true if unknown string matches the 
        /// regular expression defined by type
        /// </summary>
        /// <param name="type">ValidationTypes enum</param>
        /// <param name="unknown">String to validate</param>
        /// <returns>True if string validates</returns>
        public static bool Process(ValidationTypes type, string unknown)
        {
            string test = RegexStrings[(int)type].ToString();
            // Create a new Regex object.
            Regex r = new Regex(RegexStrings[(int)type].ToString());
            // Find a single match in the string.
            Match m = r.Match(unknown);
            return m.Success;
        }
        /// <summary>
        /// This code is used to validate the Zip
        /// </summary>
        /// <param name="TextBox"></param>
        /// <returns></returns>
        public static bool ValidateZip(string TextBox)
        {
            String ZipRegex = @"^\d{5}$";
            if (Regex.IsMatch(TextBox, ZipRegex))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
